package futbol.tacticas.concursantes.TacticaHerzo;

import futbol.General;
import futbol.tacticas.*;
import futbol.tacticas.concursantes.Tactica;

import java.awt.Color;
import java.awt.Point;
import java.util.Vector;

public class TacticaHerzo implements Tactica {
    private final int ancho = 320;
    private final int alto = 240;
    private final int arco = 60;
    
    private final int parametrizacionCampo = 8;
    private final double anguloMinimo = 0.075;
    private final double multplicadorDesvio = 1 / 6;
    private final int tDesmarqueDelanteros = 15;
    private final double maximaDistanciaDesmarque = 20;
    
    private int golesMios, golesContrario, golDe;
    private boolean esGol = true;
    private int tiempo;
    
    private final float arqueroDistanciaParaSalir = 60;
    private final float arqueroDistanciaSalir = 30;
    
    private Point bolaAnterior;
    private double bolaAngulo;
    private int bolaVelocidad;
    private boolean bolaPosesion;
    boolean bolaContrarioPosesion;
    private double[][] bolaPrediccion;
    private Point bolaUltimoGolpe;

    private int[][] jugadoresPosiciones = {
    		{-155,0},
            {-100,50},
            {-90,-60},
            {-90,60},
            {-60,-25},
            {-100,-50},
            {-10,20},
            {-60,25},
            {100,20},
            {-10,-20},
            {85,-50}
    };
    private int[] jugadoresFuerza = { 7, 7, 7, 7, 7, 7, 6, 7, 7, 6, 7};
    private int[] jugadoresOrdenDesdeArriba = {8, 10, 9, 6, 7, 4, 3, 2, 1, 5,
    		0};
    private boolean[] jugadoresAccionBola;
    private boolean[] jugadoresCercanos;
    private int[] jugadoresIntercepciones = {1, 2};
    
    private int posicionTodos;
    private int posicionArquero;
    private int posicionAtaque;
    private double[][] desmarqueDelanteros = new double[2][2];
    private int tipoIntercepciones;
    
    private int[] estadisticasTodos = new int[2];
    private int[] estadisticasAtaque = new int[3];
    private int[] estadisticasArquero = new int[3];
    private int[] estadisticasIntercepciones = new int[3];
    
    private double contrariosPromedioVelocidades;
    private Point[] contrariosPosicionesAnteriores;
    private int[] contrariosVelocidad = new int[11];
    private int[][] contrariosGoles =
    		new int[(this.ancho / 2) / this.parametrizacionCampo][this.alto /
    		this.parametrizacionCampo];
    
    public String getNombre(){
        return("Herzo");
    }
    
    public Color getColor1(){
        return(new Color(0.5f, 0.6f, 1.0f));
    }
    
    public Color getColor2(){
    	return(new Color(0.0f, 0.0f, 0.7f));
    }
    
    public Color getColorNumero(){
        return(Color.WHITE);
    }
    
    public int getFuerza(int n){
        return(this.jugadoresFuerza[n]);
    }
    
    public int getVelocidad(int n){
        return(10 - this.jugadoresFuerza[n]);
    }
    
    public int getXInicial(int n){
        return(this.jugadoresPosiciones[n][0]);
    }
    
    public int getYInicial(int n){
        return(this.jugadoresPosiciones[n][1]);
    }
    
    private void posicionTodos() {
        if (this.esGol) {
        	this.estadisticasTodos[this.posicionTodos] += this.golDe;
        	int mejor = 0;
        	for (int i = 0; i < this.estadisticasTodos.length; i++) {
        		if (this.estadisticasTodos[i] >
        				this.estadisticasTodos[mejor] ||
        				(this.estadisticasTodos[i] ==
        				this.estadisticasTodos[mejor] &&
        				mejor == this.posicionTodos)) {
        			mejor = i;
        		}
        	}
	    	switch (this.posicionTodos = mejor) {
				case 0:
					jugadoresPosiciones[0][0] = -155;
					jugadoresPosiciones[0][1] = 0;
					jugadoresPosiciones[1][0] = -110;
					jugadoresPosiciones[1][1] = 20;
					jugadoresPosiciones[2][0] = -90;
					jugadoresPosiciones[2][1] = -60;
					jugadoresPosiciones[3][0] = -90;
					jugadoresPosiciones[3][1] = 60;
					jugadoresPosiciones[4][0] = -30;
					jugadoresPosiciones[4][1] = -25;
					jugadoresPosiciones[5][0] = -110;
					jugadoresPosiciones[5][1] = -20;
					jugadoresPosiciones[6][0] = -20;
					jugadoresPosiciones[6][1] = 70;
					jugadoresPosiciones[7][0] = -30;
					jugadoresPosiciones[7][1] = 25;
					jugadoresPosiciones[8][0] = 100;
					jugadoresPosiciones[8][1] = 20;
					jugadoresPosiciones[9][0] = 20;
					jugadoresPosiciones[9][1] = -70; 
					jugadoresPosiciones[10][0] = 85;
					jugadoresPosiciones[10][1] = -50;
					break;
				case 1:
					jugadoresPosiciones[0][0] = -155;
					jugadoresPosiciones[0][1] = 0;
					jugadoresPosiciones[1][0] = -100;
					jugadoresPosiciones[1][1] = 50;
					jugadoresPosiciones[2][0] = -90;
					jugadoresPosiciones[2][1] = -60;
					jugadoresPosiciones[3][0] = -90;
					jugadoresPosiciones[3][1] = 60;
					jugadoresPosiciones[4][0] = -60;
					jugadoresPosiciones[4][1] = -25;
					jugadoresPosiciones[5][0] = -100;
					jugadoresPosiciones[5][1] = -50;
					jugadoresPosiciones[6][0] = -10;
					jugadoresPosiciones[6][1] = 20;
					jugadoresPosiciones[7][0] = -60;
					jugadoresPosiciones[7][1] = 25;
					jugadoresPosiciones[8][0] = 100;
					jugadoresPosiciones[8][1] = 20;
					jugadoresPosiciones[9][0] = -10;
					jugadoresPosiciones[9][1] = -20;
					jugadoresPosiciones[10][0] = 85;
					jugadoresPosiciones[10][1] = -50;
		            break;
	    	}
        }
    }
    
    private void posicionArquero() {
        if (this.esGol) {
        	this.estadisticasArquero[this.posicionArquero] += this.golDe;
        	int mejor = 0;
        	for (int i = 0; i < this.estadisticasArquero.length; i++) {
        		if (this.estadisticasArquero[i] >
        				this.estadisticasArquero[mejor] ||
        				(this.estadisticasArquero[i] ==
        				this.estadisticasArquero[mejor] &&
        				mejor == this.posicionArquero)) {
        			mejor = i;
        		}
        	}
	    	switch (this.posicionArquero = mejor) {
				case 0:
					this.jugadoresPosiciones[0][0] = -155;
					this.jugadoresPosiciones[0][1] = 0;
					break;
				case 1:
					int iMax = 0;
					int jMax = 0;
					this.jugadoresPosiciones[0][0] = -60;
					this.jugadoresPosiciones[0][1] = 0;
		        	for(int i = 0; i < (this.ancho / 2) /
		        			this.parametrizacionCampo; i++) {
		        		for (int j = 0; j < this.alto /
		        				this.parametrizacionCampo; j++) {
		        			if (this.contrariosGoles[i][j] >
		        					this.contrariosGoles[iMax][jMax]) {
		        				iMax = i;
		        				jMax = j;
		        				this.jugadoresPosiciones[0][0] = - this.ancho /
		        						2 + iMax * 8 + this.parametrizacionCampo
		        						/ 2;
		        				this.jugadoresPosiciones[0][1] = - this.alto / 2
		        						+ jMax * 8 + this.parametrizacionCampo /
		        						2;
		        			}
		        		}
		        	}
		        	
					break;
				case 2:
					this.jugadoresPosiciones[0][0] = -60;
					this.jugadoresPosiciones[0][1] = 0;
					break;
	    	}
        }
    }
    
    private void posicionAtaque() {
        if (this.esGol) {
        	this.estadisticasAtaque[this.posicionAtaque] += this.golDe;
        	int mejor = 0;
        	for (int i = 0; i < this.estadisticasAtaque.length; i++) {
        		if (this.estadisticasAtaque[i] >
        				this.estadisticasAtaque[mejor] ||
        				(this.estadisticasAtaque[i] ==
        				this.estadisticasAtaque[mejor] &&
        				mejor == this.posicionAtaque)) {
        			mejor = i;
        		}
        	}
	    	switch (this.posicionAtaque = mejor) {
	    		case 0:
	    			this.jugadoresPosiciones[8][0] = 80;
	    			this.jugadoresPosiciones[8][1] = 20;
	    			this.jugadoresPosiciones[10][0] = 80;
	    			this.jugadoresPosiciones[10][1] = -20;
	    			break;
	    		case 1:
	    			this.jugadoresPosiciones[8][0] = 90;
	    			this.jugadoresPosiciones[8][1] = 0;
	    			this.jugadoresPosiciones[10][0] = 65;
	    			this.jugadoresPosiciones[10][1] = -50;
	    			break;
	    		case 2:
	    			this.jugadoresPosiciones[8][0] = 90;
	    			this.jugadoresPosiciones[8][1] = 20;
	    			this.jugadoresPosiciones[10][0] = 65;
	    			this.jugadoresPosiciones[10][1] = -40;
	    			break;
	    	}
        }
    }
    
    private void desmarqueDelanteros() {
    	if (this.tiempo % this.tDesmarqueDelanteros == 0) {
    		for (int i = 0; i < 2; i++) {
	    		double angulo = Math.random() * 2 * Math.PI;
	    		double distancia = Math.random() *
	    				this.maximaDistanciaDesmarque;
	    		this.desmarqueDelanteros[i][0] = Math.cos(angulo) * distancia;
	    		this.desmarqueDelanteros[i][0] = Math.sin(angulo) * distancia;
    		}
    	}
    }
    
    private void tipoIntercepciones() {
        if (this.esGol) {
        	this.estadisticasIntercepciones[this.tipoIntercepciones] +=
        		this.golDe;
        	int mejor = 0;
        	for (int i = 0; i < this.estadisticasIntercepciones.length; i++) {
        		if (this.estadisticasIntercepciones[i] >
        				this.estadisticasIntercepciones[mejor] ||
        				(this.estadisticasIntercepciones[i] ==
        				this.estadisticasIntercepciones[mejor] &&
        				mejor == this.tipoIntercepciones)) {
        			mejor = i;
        		}
        	}
	    	switch (this.tipoIntercepciones = mejor) {
	    		case 0:
	    			this.jugadoresIntercepciones[0] = 2;
	    			this.jugadoresIntercepciones[1] = 3;
	    			break;
	    		case 1:
	    			this.jugadoresIntercepciones[0] = 2;
	    			this.jugadoresIntercepciones[1] = 5;
	    			break;
	    		case 2:
	    			this.jugadoresIntercepciones[0] = 1;
	    			this.jugadoresIntercepciones[1] = 2;
	    			break;
	    	}
        }
    }

    private double[] calcularRebotes(double posicion[], double angulo) {
        if (posicion[0] > this.ancho / 2){
        	posicion[0] = this.ancho - posicion[0];
        	angulo = General.corregirAngulo(Math.PI - angulo);
        }
        if (posicion[0] < -this.ancho / 2){
        	posicion[0] = -this.ancho - posicion[0];
        	angulo = General.corregirAngulo(Math.PI - angulo);
        }
        if (posicion[1] > this.alto / 2){
        	posicion[1] = this.alto - posicion[1];
        	angulo = General.corregirAngulo(-angulo);
        }
        if (posicion[1] < -this.alto / 2){
        	posicion[1] = -this.alto - posicion[1];
        	angulo = General.corregirAngulo(-angulo);
        }
        double bola[] = new double[3];
        bola[0] = posicion[0];
        bola[1] = posicion[1];
        bola[2] = angulo;
        return(bola);
    }
    
    private double[][] predecirBolas(SituacionJugadores sj, double velocidad,
    		double angulo) {
        double bolaTAngulo = angulo;
        double bola[][] = new double[23][2];
        bola[0][0] = sj.getBola().getX();
        bola[0][1] = sj.getBola().getY();
        for (int t = 1; t < 23; t++) {
        	bola[t][0] = bola[t - 1][0] + (Math.max(velocidad - t + 1, 0)) *
        			Math.cos(bolaTAngulo);
        	bola[t][1] = bola[t - 1][1] + (Math.max(velocidad - t + 1, 0)) *
        			Math.sin(bolaTAngulo);
        	double nuevaBola[] = calcularRebotes(bola[t], bolaTAngulo);
        	bola[t][0] = nuevaBola[0];
        	bola[t][1] = nuevaBola[1];
            bolaTAngulo = nuevaBola[2];
        }
    	return(bola);
    }
    
    private double[][] predecirBolas(SituacionJugadores sj) {
    	return(this.predecirBolas(sj, this.bolaVelocidad, this.bolaAngulo));
    }
    
    private double[] predecirBola(int t, double[][] prediccion) {
    	return(prediccion[Math.max(0, Math.min(t, 22))]);
    }

    private double[] predecirBola(int t) {
        return(this.predecirBola(t, this.bolaPrediccion));
    }

    private void calcularMarcador(SituacionJugadores sj) {
        this.esGol = false;
        if (sj.getBola().getY() > -30 && sj.getBola().getY() < 30) {
            if (sj.getBola().getX() >= 160) {
                this.golesMios++;
                this.golDe = 1;
                this.esGol = true;
            } else if (sj.getBola().getX() <= -160) {
                this.golesContrario++;
                this.golDe = -1;
                this.esGol = true;
            }
        }
    }

    private void estudiarContrarios(SituacionJugadores sj) {
        if (!this.esGol) {
        	this.contrariosPromedioVelocidades = 0;
            for (int i = 0; i < 11; i++) {
                for (int j = 0; j < 2; j++) {
                	double angulo = General.corregirAngulo(General.getAngulo(
                            this.contrariosPosicionesAnteriores[i].getX(),
                            this.contrariosPosicionesAnteriores[i].getY(),
                            sj.getContrario()[i].getX(),
                            sj.getContrario()[i].getY()));
                    int velocidad = (int) Math.round(General.getDistancia(
                            this.contrariosPosicionesAnteriores[i].getX(),
                            this.contrariosPosicionesAnteriores[i].getY(),
                            sj.getContrario()[i].getX(),
                            sj.getContrario()[i].getY()));
                    if (velocidad > this.contrariosVelocidad[i] &&
                    		velocidad <= 6 && Math.abs((angulo / (Math.PI / 2))
                    		% 1) < this.anguloMinimo / (Math.PI / 2)) {
                        this.contrariosVelocidad[i] = velocidad;
                    }
                }
                this.contrariosPromedioVelocidades +=
                		this.contrariosVelocidad[i];
            }
            this.contrariosPromedioVelocidades /= 11; 
        } else if (this.golDe == -1) {
        	if (this.bolaUltimoGolpe.getX() < 0) {
            this.contrariosGoles[(int) ((this.bolaUltimoGolpe.getX() +
            		this.ancho / 2) / this.parametrizacionCampo)][(int)
            		((this.bolaUltimoGolpe.getY() + this.alto / 2) /
            		this.parametrizacionCampo)]++;
        	}
        }
        this.contrariosPosicionesAnteriores = sj.getContrario();
    }

    private void estudiarBola(SituacionJugadores sj) {
        if (this.esGol) {
            this.bolaAnterior = sj.getBola();
            this.bolaAngulo = 0;
            this.bolaVelocidad = 0;
        } else {
        	double angulo = General.getAngulo(this.bolaAnterior.getX(),
                    this.bolaAnterior.getY(), sj.getBola().getX(),
                    sj.getBola().getY());
        	int velocidad = (int) General.getDistancia(sj.getBola().getX(),
            		sj.getBola().getY(), this.bolaAnterior.getX(),
                    this.bolaAnterior.getY());
        	if (sj.getBola().getX() > - this.ancho / 2 + 1 && ( (velocidad >=
        			this.bolaVelocidad + 1 && this.bolaVelocidad < 15) ||
        			Math.abs(this.bolaAngulo - angulo) > this.anguloMinimo)) {
        		this.bolaUltimoGolpe = sj.getBola();
        	}
        	this.bolaAngulo = General.getAngulo(this.bolaAnterior.getX(),
                    this.bolaAnterior.getY(), sj.getBola().getX(),
                    sj.getBola().getY());
            this.bolaVelocidad = (int) General.getDistancia(sj.getBola().getX(),
            		sj.getBola().getY(), this.bolaAnterior.getX(),
                    this.bolaAnterior.getY());
        }
        this.bolaPrediccion = this.predecirBolas(sj);
        this.bolaPosesion = false;
        this.jugadoresCercanos = new boolean[11];
       	int jugadorCercano = sj.getMasCercanoDeBola();
       	if (General.getDistancia(sj.getBola().getX(), sj.getBola().getY(),
            	sj.getMisJugadores()[jugadorCercano].getX(),
            	sj.getMisJugadores()[jugadorCercano].getY()) < 10 + 2 &&
            	this.bolaVelocidad < 15) {
            this.bolaPosesion = true;
            for (int i = 0; i < 11; i++) {
            	if (General.getDistancia(sj.getBola().getX(),
            			sj.getBola().getY(), sj.getMisJugadores()[i].getX(),
                    	sj.getMisJugadores()[i].getY()) < 10 + 2) {
            		this.jugadoresCercanos[i] = true;
            	}
            }
       	}
        this.bolaContrarioPosesion = false;
        Point contrarioCercano = sj.getContrario()[sj.getContrarioMasCerca(
        		sj.getBola().getX(), sj.getBola().getY())];
        if (General.getDistancia(contrarioCercano.getX(),
        		contrarioCercano.getY(), sj.getBola().getX(),
        		sj.getBola().getY()) < 10 + 2) {
        	this.bolaContrarioPosesion = true;
        }
        this.bolaAnterior = sj.getBola();
    }

    private void intentarIntercepcion(Vector<Comando> comandos,
    		SituacionJugadores sj, int jugadores) {
    	double[][] intercepciones = new double[11][3];
    	int jugadoresCalculados = 0;
    	for (int i = 0; i < 11; i++) {
    		intercepciones[i][0] = -1;
    	}
    	int tInicial = Math.max(this.bolaVelocidad - 14, 0);
    	for (int t = tInicial; t < tInicial + 100 && jugadoresCalculados <
    			jugadores; t++) {
            double bola[] = this.predecirBola(t);
            for (int i = 1; i < 11 && jugadoresCalculados < jugadores; i++) {
            	if (General.getDistancia(bola[0], bola[1],
            			sj.getMisJugadores()[i].getX(),
            			sj.getMisJugadores()[i].getY()) - t *
            			this.getVelocidad(i) < 10 + 2 &&
            			intercepciones[i][0] == -1) {
            		intercepciones[i][0] = (double) t; 
            		intercepciones[i][1] = bola[0];
            		intercepciones[i][2] = bola[1];
            		jugadoresCalculados++;
            	}
            }
    	}
        int[] interceptor = new int[Math.min(jugadores, 11)];
        for (int i = 0; i < jugadores && i < 11; i++) {
        	interceptor[i] = -1;
        }
        for (int i = 0; i < 11; i++) {
        	if (intercepciones[this.jugadoresOrdenDesdeArriba[i]][0] != -1) {
		    	for (int j = 0; j < jugadores; j++) {
		    		if (interceptor[j] == -1 ||
		    				intercepciones[this.jugadoresOrdenDesdeArriba[i]][0]
		    				<= intercepciones[interceptor[j]][0]) {
		    			for (int k = jugadores - 1; k > j ; k--) {
		    				interceptor[k] = interceptor[k - 1];
		    			}
		    			interceptor[j] = this.jugadoresOrdenDesdeArriba[i];
		    			break;
		    		}
		    	}
        	}
        }
        for (int i = 0; i < jugadores && i < 11 && interceptor[i] != -1; i++) {
        	comandos.add(new ComandoIrA(interceptor[i],
        			intercepciones[interceptor[i]][1],
	       			intercepciones[interceptor[i]][2]));
        }
    }

    private double[] distanciaAPosicion(double pos1X, double pos1Y,
    		double pos2X, double pos2Y, double distancia) {
        double angulo = General.getAngulo(pos1X, pos1Y, pos2X, pos2Y);
        double distanciaAPos2[] = new double[2];
        distanciaAPos2[0] = pos1X + distancia * Math.cos(angulo);
        distanciaAPos2[1] = pos1Y + distancia * Math.sin(angulo);
        return(distanciaAPos2);
    }

    private void moverArquero(Vector<Comando> comandos, SituacionJugadores sj) {
    	boolean salir = false;
    	for (int i = 0; i < 11 && !salir; i++) {
    		if (General.getDistancia(
    				this.contrariosPosicionesAnteriores[i].getX(),
    				this.contrariosPosicionesAnteriores[i].getY(), -this.ancho /
    				2, 0) < this.arqueroDistanciaParaSalir * 2 &&
    				General.getDistancia(
    	    		this.contrariosPosicionesAnteriores[i].getX(),
    	    		this.contrariosPosicionesAnteriores[i].getY(), 0, 0) < 20) {
    			salir = true;
    		}
    	}
        if (General.getDistancia(-this.ancho / 2, 0, sj.getBola().getX(),
        		sj.getBola().getY()) <= this.arqueroDistanciaParaSalir &&
        		salir) {
            double posicion[] = distanciaAPosicion((int) (-this.ancho / 2), 0,
            		sj.getBola().getX(), sj.getBola().getY(),
            		arqueroDistanciaSalir);
            comandos.add(new ComandoIrA(0, posicion[0], posicion[1]));
        } else if (General.getDistancia(-this.ancho / 2, 0, sj.getBola().getX(),
        		sj.getBola().getY()) <= this.arqueroDistanciaParaSalir) {
        	double[] bola = this.predecirBola(1);
            if (bola[1] < -30) {
                comandos.add(new ComandoIrA(0, this.getXInicial(0), -30));
            } else if (bola[1] > 30) {
                comandos.add(new ComandoIrA(0, this.getXInicial(0), 30));
            } else {
                comandos.add(new ComandoIrA(0, this.getXInicial(0), bola[1]));
            }        
        } else {
        	double[] bola = this.predecirBola(1);
            double posicion[] = distanciaAPosicion((int) (-this.ancho / 2), 0,
            		bola[0], bola[1], arqueroDistanciaSalir);
            comandos.add(new ComandoIrA(0, this.getXInicial(0), posicion[1]));
        }
    }

    private void posicionarJugadores(Vector<Comando> comandos,
    		SituacionJugadores sj) {
    	double[] bola = this.predecirBola(1);
    	double[] desplazamientoSegunBola = new double[2];
    	int jugadoresPosesion = 0;
    	for (int i = 0; i < 11 && jugadoresPosesion != -1; i++) {
    		if (this.jugadoresCercanos[i]) {
    			if (jugadoresPosesion == 0) {
        			jugadoresPosesion = i;	
    			} else {
    				jugadoresPosesion = -1;
    			}
    		}
    	}
    	int distancia1Min;
		int distancia1Max;
		int distancia2Min;
		int distancia2Max;
		int distanciaMaxima;
		if (jugadoresPosesion != -1 && this.getFuerza(jugadoresPosesion) ==
				6) {
			distancia1Min = 45;
			distancia1Max = 85;
			distancia2Min = 165;
			distancia2Max = 215;
			distanciaMaxima = 66;
		} else {
			distancia1Min = 100;
			distancia1Max = 150;
			distancia2Min = 225;
			distancia2Max = 275;
			distanciaMaxima = 126;
		}
    	for (int i = 0; i < 11; i++) {
    		double distancia = General.getDistancia(
    				sj.getMisJugadores()[i].getX(),
    				sj.getMisJugadores()[i].getY(), sj.getBola().getX(),
    				sj.getBola().getY());
    		if (sj.getMisJugadores()[i].getX() > sj.getBola().getX() &&
    				distancia > distancia1Min && distancia < distancia1Max) {
    			double[] posicionFinal = this.distanciaAPosicion(
    					sj.getBola().getX(),  sj.getBola().getY(),
    					sj.getMisJugadores()[i].getX(),
    					sj.getMisJugadores()[i].getY(), distanciaMaxima);
    			comandos.add(new ComandoIrA(i, posicionFinal[0],
    					posicionFinal[1]));
    		} else if (sj.getMisJugadores()[i].getX() > sj.getBola().getX() &&
    				distancia > distancia2Min && distancia < distancia2Max) {
    			double[] posicionFinal = this.distanciaAPosicion(
    					sj.getBola().getX(),  sj.getBola().getY(),
    					sj.getMisJugadores()[i].getX(),
    					sj.getMisJugadores()[i].getY(), distanciaMaxima * 2);
    			comandos.add(new ComandoIrA(i, posicionFinal[0],
    					posicionFinal[1]));
    		} else {
    			float x = this.getXInicial(i);
    			float y = this.getYInicial(i);
    			if (i == 8) {
    				x += this.desmarqueDelanteros[0][0];
    				y += this.desmarqueDelanteros[0][1];
    			} else if (i == 10) {
    				x += this.desmarqueDelanteros[1][0];
    				y += this.desmarqueDelanteros[1][1];
    			}
    			desplazamientoSegunBola[0] = Math.signum(bola[0] - x) *
    					Math.pow(Math.abs(bola[0] - x), 0.5);
        		desplazamientoSegunBola[1] = Math.signum(bola[1] - y) *
        				Math.pow(Math.abs(bola[1] - y), 0.5);
    			comandos.add(new ComandoIrA(i, x + desplazamientoSegunBola[0],
    					y + desplazamientoSegunBola[1]));
    		}
    	}
    }

    private void marcasPersonales(Vector<Comando> comandos,
    		SituacionJugadores sj) {
    	for (int i = 0; i < 11; i++) {
    		if (sj.getContrario()[i].getX() < 0 &&
    				10 - this.contrariosVelocidad[i] >= 7) {
    			int jugador = 0;
    			double distancia = Integer.MAX_VALUE;
    	    	for (int j = 0; j < 11; j++) {
    	    		double distanciaAux = General.getDistancia(
    	    				sj.getContrario()[i].getX(),
    	    				sj.getContrario()[i].getY(),
    	    				this.getXInicial(this.jugadoresOrdenDesdeArriba[j]),
    	    				this.getYInicial(
    	    				this.jugadoresOrdenDesdeArriba[j]));
    	    		if (distanciaAux <= distancia) {
    	    			jugador = this.jugadoresOrdenDesdeArriba[j];
    	    			distancia = distanciaAux;
    	    		}
    	    	}
    	    	comandos.add(new ComandoIrA(jugador,
    	    			sj.getContrario()[i].getX(),
    	    			sj.getContrario()[i].getY()));
    		} else if (sj.getContrario()[i].getX() < -100) {
    			int jugador = 0;
    			double distancia = 99999;
    	    	for (int j = 0; j < 11; j++) {
    	    		double distanciaAux = General.getDistancia(
    	    				sj.getContrario()[i].getX(),
    	    				sj.getContrario()[i].getY(),
    	    				this.getXInicial(this.jugadoresOrdenDesdeArriba[j]),
    	    				this.getYInicial(
    	    				this.jugadoresOrdenDesdeArriba[j]));
    	    		if (distanciaAux < distancia) {
    	    			jugador = this.jugadoresOrdenDesdeArriba[j];
    	    			distancia = distanciaAux;
    	    		}
    	    	}
    	    	comandos.add(new ComandoIrA(jugador,
    	    			sj.getContrario()[i].getX(),
    	    			sj.getContrario()[i].getY()));
    		}
    	}
    }
    
    private boolean jugadoresCercanosPendientes() {
    	for (int i = 0; i < 11; i++) {
    		if (this.jugadoresCercanos[i] && !this.jugadoresAccionBola[i]) {
    			return(true);
    		}
    	}
    	return(false);
    }
    
    private void comandoPatearAlArco(Vector<Comando> comandos,
    		SituacionJugadores sj, int jugador) {
		double angulo = General.getAngulo(sj.getBola().getX(), 
				sj.getBola().getY(), this.ancho / 2, 0);
		comandos.add(new ComandoGolpearBola(jugador, sj.getBola().getX() +
				1000 * Math.cos(angulo), sj.getBola().getY() + 1000 *
				Math.sin(angulo)));
    }

    private void patearAlArco(Vector<Comando> comandos, SituacionJugadores sj) {
    	if (this.bolaPosesion && this.jugadoresCercanosPendientes()) {
	    	for (int i = 0; i < 11; i++) {
	    		int distanciaMaxima = 0;
	    		for (int j = this.getFuerza(i) * 3; j >= 15; j--) {
	    			distanciaMaxima += j;
	    		}
	    		if (!this.jugadoresAccionBola[i] && this.jugadoresCercanos[i] &&
	    				General.getDistancia(sj.getMisJugadores()[i].getX(),
	    				sj.getMisJugadores()[i].getY(), this.ancho / 2,
	    				this.arco / 2) + 2 < distanciaMaxima &&
	    				General.getDistancia(sj.getMisJugadores()[i].getX(),
	    				sj.getMisJugadores()[i].getY(), this.ancho / 2,
	    				- this.arco / 2) + 2 < distanciaMaxima) {
	    			this.jugadoresAccionBola[i]= true;
	    			comandoPatearAlArco(comandos, sj, i);
	    		}
	    	}
    	}
    }

    private void controlBola(Vector<Comando> comandos,
    		SituacionJugadores sj) {
    	if (this.bolaPosesion && this.jugadoresCercanosPendientes()) {
			int contrario = sj.getContrarioMasCerca(sj.getBola().getX(),
					sj.getBola().getY());
	    	if (!this.bolaContrarioPosesion && General.getDistancia(
	    			sj.getBola().getX(), sj.getBola().getY(),
	    			sj.getContrario()[contrario].getX(),
	    			sj.getContrario()[contrario].getY()) > 12 + 2 *
	    			this.contrariosVelocidad[contrario]) {
	        	for (int i = 0; i < 11; i++) {
	        		if (!this.jugadoresAccionBola[i] &&
	        				this.jugadoresCercanos[i]) {
	        			double distancia;
	        			if (this.getFuerza(i) == 7) {
	        				distancia = 11;
	        			} else {
	        				distancia = 15;
	        			}
	        			this.jugadoresAccionBola[i]= true;
	        			if (sj.getMisJugadores()[i].getX() > 125) {
	    	    			double angulo = General.corregirAngulo(General.getAngulo(
	    	    					sj.getMisJugadores()[i].getX(),
	    	    					sj.getMisJugadores()[i].getY(),
	    	    					this.ancho / 2, 0));
	    	    			comandos.add(new ComandoGolpearBola(i,
	    	    					sj.getMisJugadores()[i].getX() +
	    	    					Math.cos(angulo) * distancia,
	    	    					sj.getMisJugadores()[i].getY() +
		        					Math.sin(angulo) * distancia));
	        			} else {
	    	    			comandos.add(new ComandoGolpearBola(i,
	    	    					sj.getMisJugadores()[i].getX() + distancia,
		        					sj.getMisJugadores()[i].getY()));	
	    	    		}
	        		}
	        	}
	    	}
    	}
    }
    
    private void pasar(Vector<Comando> comandos, SituacionJugadores sj) {
		if (this.bolaPosesion && this.jugadoresCercanosPendientes()) {
			boolean fuerza6 = false;
			boolean fuerza7 = false;
			for (int i = 0; i < 11 && (!fuerza7 || !fuerza6); i++) {
				if (this.jugadoresCercanos[i]) {
					if (this.getFuerza(i) == 7) {
						fuerza7 = true;
					} else {
						fuerza6 = true;
					}
				}
			}
	    	for (int fuerza = 6; fuerza <= 7; fuerza++) {
		    	double puntos = 0;
		    	double[] posicion = new double[2];
	    		if ((fuerza == 6 && !fuerza6) || (fuerza == 7 && !fuerza7)) {
	    			continue;
	    		}
		    	for (int i = 0; i < 2000; i++) {
			    	double angulo = General.corregirAngulo(- Math.PI / 2 +
			    			Math.random() * Math.PI);
			    	double distancia;
			    	if (fuerza == 6) {
			    		distancia = 121;
			    	} else {
			    		distancia = 181;
			    	}
			    	distancia = Math.random() * distancia + 50; 
			    	int nGrado=100;
			    	if (distancia < 50) {
			    		nGrado = (int) (distancia * 2);
			    	}
			        int velocidad = (int) (fuerza * nGrado / 100) * 3;
			        double[][] prediccion = this.predecirBolas(sj, velocidad,
			        		angulo);
			        double[][] prediccionD1 = this.predecirBolas(sj, velocidad,
			        		angulo - Math.PI / 10);
			        double[][] prediccionD2 = this.predecirBolas(sj, velocidad,
			        		angulo + Math.PI / 10);
			    	double[] posicionAux = this.predecirBola(22, prediccion);
			    	double[] posicionT = new double[2]; 
			    	int interceptable = 0;
			    	int atrapable = 0;
				   	for (int t = 1; interceptable == 0 && atrapable == 0;
				   			t++) {
				   		if (velocidad - t < 15) {
				   			double posicionD1[] = this.predecirBola(t,
				   					prediccionD1);
				   			double posicionD2[] = this.predecirBola(t,
				   					prediccionD2);
				   			double desvio = General.getDistancia(posicionD1[0],
				   					posicionD1[1], posicionD2[0], posicionD2[1]);
				   			desvio *= this.multplicadorDesvio;
					   		posicionT = this.predecirBola(t, prediccion);
					   		for (int j = 0; j < 11; j++) {
					    		if (General.getDistancia(posicionT[0], posicionT[1],
					    				sj.getContrario()[j].getX(),
					    				sj.getContrario()[j].getY()) - t *
					    				this.contrariosVelocidad[j] - desvio < 10 +
					    				2) {
					    			interceptable++;
					    		}
					   		}
					   		for (int j = 0; j < 11; j++) {
					    		if (General.getDistancia(posicionT[0], posicionT[1],
					    				sj.getMisJugadores()[
					    				this.jugadoresOrdenDesdeArriba[j]].getX(),
					    				sj.getMisJugadores()[
					    				this.jugadoresOrdenDesdeArriba[j]].getY())
					    				- t * this.getVelocidad(
					    				this.jugadoresOrdenDesdeArriba[j]) + desvio
					    				< 10 + 2) {
					    			atrapable++;
					    		}
					   		}
				   		}
				   	}
				   	double puntosAux = (posicionT[0] + this.ancho / 2) /
				   			this.ancho;
				   	if (fuerza == 6) {
					   	puntosAux *=  0.1;
					   	if (interceptable == 0) {
					   		puntosAux += 0.65;
					   	}				   		
				   	} else if (this.contrariosPromedioVelocidades <= 4.5) {
					   	puntosAux *=  0.3;
					   	if (interceptable == 0) {
					   		puntosAux += 0.45;
					   	}
				   	} else {
				   		puntosAux *=  0.45;
					   	if (interceptable == 0) {
					   		puntosAux += 0.3;
					   	}
				   	}
				   	puntosAux += 0.2 * (atrapable + 1) / (interceptable + atrapable + 1);
				   	angulo = General.getAngulo(posicionT[0], posicionT[1],
				   			this.ancho / 2, 0);
				   	if (angulo > Math.PI) {
				   		angulo -= Math.PI * 2;
				   	}
				   	puntosAux += 0.05 * (1 - Math.abs(angulo) / (Math.PI / 2));
				   	if (puntosAux > puntos) {
				   		puntos = puntosAux;
				   		posicion = posicionAux;
				   	}
			    }
				if (puntos > 0.8) {
					for (int i = 0; i < 11; i++) {
						if (!this.jugadoresAccionBola[i] &&
								this.jugadoresCercanos[i] && this.getFuerza(i)
								== fuerza) {
							this.jugadoresAccionBola[i] = true;
							comandos.add(new ComandoGolpearBola(i, posicion[0],
									posicion[1]));
						}
					}
				}
	    	}
		}
	}
    
    public Vector<Comando> getComandos(SituacionJugadores sj){
        Vector<Comando> comandos = new Vector<Comando>();

        this.posicionTodos();
        this.posicionArquero();
        this.posicionAtaque();
        this.desmarqueDelanteros();
        this.tipoIntercepciones();
        
        this.jugadoresAccionBola = new boolean[11];
        
        this.estudiarContrarios(sj);
        this.estudiarBola(sj);
        this.posicionarJugadores(comandos, sj);
        if (!this.bolaPosesion) {
        	if (sj.getBola().getX() > 50) {
        		this.intentarIntercepcion(comandos, sj,
        				this.jugadoresIntercepciones[0]);
        	} else {
        		this.intentarIntercepcion(comandos, sj,
        				this.jugadoresIntercepciones[1]);
        	}
        }
        this.marcasPersonales(comandos, sj);
        this.intentarIntercepcion(comandos, sj, 1);
        
        if (this.posicionArquero == 0) {
        	this.moverArquero(comandos, sj);
        	this.jugadoresAccionBola[0] = true;
        	comandos.add(new ComandoTiroAPuerta(0, 0));
        }
        
      	this.controlBola(comandos, sj);
        this.patearAlArco(comandos, sj);
      	this.pasar(comandos, sj);
      	
    	for (int i = 0; i < 11; i++) {
    		if (!this.jugadoresAccionBola[i]) {
    			this.jugadoresAccionBola[i]= true;
    			comandos.add(new ComandoTiroAPuerta(i, 0));
    		}
    	}

        this.calcularMarcador(sj);
        this.tiempo++;
        
        return(comandos);
    }
    
}
